/*
 * data.h
 *
 *  (c) by Normen Seemann
 *
 *  Created on: May 1, 2009
 *
 */

#ifndef DATA_H_
#define DATA_H_

#include <stdlib.h>
#include <new>
#include <core/exceptions.h>

namespace crossEyed
{
namespace core
{

#define CLIP(value, min, max) \
   ((value < min) ? min : ((value > max) ? max : value))

#define BYTE_CLIP(value) \
   CLIP(value, 0, 255)

class TColor
{
public:
   union { unsigned char R; unsigned char Y; } ;
   union { unsigned char G; unsigned char U; } ;
   union { unsigned char B; unsigned char V; } ;

   TColor()
      : R( 0 ), G( 0 ), B( 0 ) {} ;
   TColor( unsigned char c1, unsigned char c2, unsigned char c3 )
      : R( c1 ), G( c2 ), B( c3 ) {} ;

   inline void convertToRGB( TColor & res )
   {
      long C = (long)Y << 8;
      long D = (long)U - 128;
      long E = (long)V - 128;

      res.R = BYTE_CLIP(( C            + 359 * E ) >> 8);
      res.G = BYTE_CLIP(( C  - 183 * D -  88 * E ) >> 8);
      res.B = BYTE_CLIP(( C  + 454 * D           ) >> 8);
   } ;
};

//
// TRepresentation
//
class TRepresentation
{
public:
   TRepresentation() { } ;
   ~TRepresentation() { } ;
};

//
// TAnyBuffer
//
// Represents a buffer.
//
template <class CELL>
class TAnyBuffer : public TRepresentation
{
protected:
   CELL *  pBuffer ;
   size_t  size ;

public:
   TAnyBuffer() { pBuffer = NULL; size = 0; } ;
   TAnyBuffer(size_t size) ;
   ~TAnyBuffer() ;

   size_t getSize() const { return size ; } ;
   CELL * getBuffer() const { return pBuffer ; } ;
};

//
// TFrameBuffer
//
// Represents a rectangular frame buffer.
//
template <class CELL>
class TFrameBuffer : public TAnyBuffer<CELL>
{
protected:
   unsigned int width ;
   unsigned int height ;

public:
   TFrameBuffer( ) { width = 0; height = 0; } ;
   TFrameBuffer( unsigned int width, unsigned int height ) ;
   ~TFrameBuffer() { } ;

   unsigned int getWidth() { return width ; } ;
   unsigned int getHeight() { return height ; } ;

   CELL& operator() (unsigned int x, unsigned int y) ;
   CELL operator() (unsigned int x, unsigned int y) const ;
};

//
// Inlines
//
//
// TAnyBuffer inlines
//

template<class CELL>
inline TAnyBuffer<CELL>::TAnyBuffer(size_t size) : size( size )
{
   try {
      pBuffer = new CELL[ size ] ;
   }
   catch(std::bad_alloc& badAlloc)
   {
      XI_OOM_HARD;
   }
} ;

template<class CELL>
inline TAnyBuffer<CELL>::~TAnyBuffer()
{
   if ( pBuffer != NULL )
   {
      delete[] pBuffer ;
   }
}

//
// TFrameBuffer inlines
//

template<class CELL>
TFrameBuffer<CELL>::TFrameBuffer( unsigned int width, unsigned int height )
   : TAnyBuffer<CELL>( width * height ),
     width( width ), height( height )
{ } ;

template<class CELL>
inline CELL& TFrameBuffer<CELL>::operator() (unsigned int x, unsigned int y)
{
//   if (x >= width || y >= height)
//     throw BadIndex("Matrix subscript out of bounds");
   return this->pBuffer[ y * width + x ] ;
}

template<class CELL>
inline CELL TFrameBuffer<CELL>::operator() (unsigned int x, unsigned int y) const
{
//   if (x >= width || y >= height)
//     throw BadIndex("Matrix subscript out of bounds");
   return this->pBuffer[ y * width + x ] ;
}

typedef TFrameBuffer<unsigned char> TByteFrameBuffer ;

class TLuminanceToLuminancePixelAdapter
{
protected:
   TByteFrameBuffer * pFrame ;
   unsigned char    * pCurMacroPixel ;

public:
   inline TLuminanceToLuminancePixelAdapter( TByteFrameBuffer * pFrame )
      : pFrame( pFrame ),
        pCurMacroPixel( pFrame->getBuffer() ) {};

   inline void toTarget( unsigned char aDestPixel[] )
   {
      aDestPixel[0] = *((unsigned char *)pFrame );
   }

   inline TLuminanceToLuminancePixelAdapter & operator ++ (int)
   {
      pCurMacroPixel++ ;
      return *this ;
   }

   static inline size_t getBytesPerMacroPixel()
   {
      return sizeof( unsigned char ) ;
   }

   static inline size_t getPixelsPerMacroPixel()
   {
      return 1 ;
   }
};

}}
#endif /* DATA_H_ */
